home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / snip1292.zip / EVAL.C < prev    next >
C/C++ Source or Header  |  1992-12-26  |  7KB  |  315 lines

  1. /*
  2. **  EVAL.C - A simple mathematical expression evaluator in C
  3. **
  4. **  operators supported: (
  5. **                       )
  6. **                       +
  7. **                       -
  8. **                       *
  9. **                       /
  10. **                       ^
  11. **
  12. **  limitations: 1 - No precedence rules are implemented.
  13. **               2 - Numbers can be negated (e.g. "-13"), but not
  14. **                   expressions (e.g. "-(13)").
  15. **
  16. **  Original Copyright 1991 by Bob Stout as part of
  17. **  the MicroFirm Function Library (MFL)
  18. **
  19. **  This subset* version is hereby donated to the public domain.
  20. **
  21. **  *(The MFL version adds 150 lines of code, 5 level precedence,
  22. **    logarithmic and transcendental operators, pi as a constant,
  23. **    named variables, and fully understands negation.)
  24. */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <ctype.h>
  30. #include <math.h>
  31.  
  32. #define NUL '\0'
  33.  
  34. typedef enum {R_ERROR = -2 /* range */, ERROR /* syntax */, SUCCESS} STATUS;
  35.  
  36. static char   delims[]   = "+-*/^)(";           /* Tokens               */
  37. static char   op_stack[256];                    /* Operator stack       */
  38. static double arg_stack[256];                   /* Argument stack       */
  39. static char   token[256];                       /* Token buffer         */
  40. static int    op_sptr,                          /* op_stack pointer     */
  41.               arg_sptr,                         /* arg_stack pointer    */
  42.               parens,                           /* Nesting level        */
  43.               state = 0;                        /* 0 = Awaiting expression
  44.                                                    1 = Awaiting operator
  45.                                                 */
  46.  
  47. int evaluate(char *, double *);
  48.  
  49. static int        do_op(void);
  50. static int        do_paren(void);
  51. static void       push_op(char);
  52. static void       push_arg(double);
  53. static STATUS     pop_arg(double *);
  54. static STATUS     pop_op(int *);
  55. static char      *getexp(char *);
  56. static char      *getop(char *);
  57. static void       pack(char *);
  58.  
  59. #ifdef TEST
  60.  
  61. void main(int argc, char *argv[])
  62. {
  63.       double val;
  64.  
  65.       printf("evaluate(%s) ", argv[1]);
  66.       printf("returned %d\n", evaluate(argv[1], &val));
  67.       printf("val = %f\n", val);
  68. }
  69.  
  70. #endif
  71.  
  72. /*
  73. **  Evaluate a mathematical expression
  74. */
  75.  
  76. int evaluate(char *line, double *val)
  77. {
  78.       double arg;
  79.       char *ptr = line, *str, *endptr;
  80.       int ercode;
  81.  
  82.       pack(line);
  83.  
  84.       while (*ptr)
  85.       {
  86.             switch (state)
  87.             {
  88.             case 0:
  89.                   if (NULL != (str = getexp(ptr)))
  90.                   {
  91.                         if ('(' == *str)
  92.                         {
  93.                               push_op(*str);
  94.                               ptr += strlen(str);
  95.                               break;
  96.                         }
  97.  
  98.                         if (0.0 == (arg = strtod(str, &endptr)) &&
  99.                               NULL == strchr(str, '0'))
  100.                         {
  101.                               return ERROR;
  102.                         }
  103.                         push_arg(arg);
  104.                         ptr += strlen(str);
  105.                   }
  106.                   else  return ERROR;
  107.  
  108.                   state = 1;
  109.                   break;
  110.  
  111.             case 1:
  112.                   if (NULL == (str = getop(ptr)))
  113.                         return ERROR;
  114.  
  115.                   if (strchr(delims, *str))
  116.                   {
  117.                         if (')' == *str)
  118.                         {
  119.                               if (SUCCESS > (ercode = do_paren()))
  120.                                     return ercode;
  121.                         }
  122.                         else
  123.                         {
  124.                               push_op(*str);
  125.                               state = 0;
  126.                         }
  127.  
  128.                         ptr += strlen(str);
  129.                   }
  130.                   else  return ERROR;
  131.  
  132.                   break;
  133.             }
  134.       }
  135.  
  136.       while (1 < arg_sptr)
  137.       {
  138.             if (SUCCESS > (ercode = do_op()))
  139.                   return ercode;
  140.       }
  141.       if (!op_sptr)
  142.             return pop_arg(val);
  143.       else  return ERROR;
  144. }
  145.  
  146. /*
  147. **  Evaluate stacked arguments and operands
  148. */
  149.  
  150. static int do_op(void)
  151. {
  152.       double arg1, arg2;
  153.       int op;
  154.  
  155.       if (ERROR == pop_op(&op))
  156.             return ERROR;
  157.  
  158.       pop_arg(&arg1);
  159.       pop_arg(&arg2);
  160.  
  161.       switch (op)
  162.       {
  163.       case '+':
  164.             push_arg(arg2 + arg1);
  165.             break;
  166.  
  167.       case '-':
  168.             push_arg(arg2 - arg1);
  169.             break;
  170.  
  171.       case '*':
  172.             push_arg(arg2 * arg1);
  173.             break;
  174.  
  175.       case '/':
  176.             if (0.0 == arg1)
  177.                   return R_ERROR;
  178.             push_arg(arg2 / arg1);
  179.             break;
  180.  
  181.       case '^':
  182.             if (0.0 > arg2)
  183.                   return R_ERROR;
  184.             push_arg(pow(arg2, arg1));
  185.             break;
  186.  
  187.       case '(':
  188.             arg_sptr += 2;
  189.             break;
  190.  
  191.       default:
  192.             return ERROR;
  193.       }
  194.       if (1 > arg_sptr)
  195.             return ERROR;
  196.       else  return op;
  197. }
  198.  
  199. /*
  200. **  Evaluate one level
  201. */
  202.  
  203. static int do_paren(void)
  204. {
  205.       int op;
  206.  
  207.       if (1 > parens--)
  208.             return ERROR;
  209.       do
  210.       {
  211.             if (SUCCESS > (op = do_op()))
  212.                   break;
  213.       } while ('('!= op);
  214.       return op;
  215. }
  216.  
  217. /*
  218. **  Stack operations
  219. */
  220.  
  221. static void push_op(char op)
  222. {
  223.       if ('(' == op)
  224.             ++parens;
  225.       op_stack[op_sptr++] = op;
  226. }
  227.  
  228. static void push_arg(double arg)
  229. {
  230.       arg_stack[arg_sptr++] = arg;
  231. }
  232.  
  233. static STATUS pop_arg(double *arg)
  234. {
  235.       *arg = arg_stack[--arg_sptr];
  236.       if (0 > arg_sptr)
  237.             return ERROR;
  238.       else  return SUCCESS;
  239. }
  240.  
  241. static STATUS pop_op(int *op)
  242. {
  243.       if (!op_sptr)
  244.             return ERROR;
  245.       *op = op_stack[--op_sptr];
  246.       return SUCCESS;
  247. }
  248.  
  249. /*
  250. **  Get an expression
  251. */
  252.  
  253. static char *getexp(char *str)
  254. {
  255.       char *ptr = str, *tptr = token;
  256.  
  257.       while (*ptr)
  258.       {
  259.             if (strchr(delims, *ptr))
  260.             {
  261.                   if ('-' == *ptr)
  262.                   {
  263.                         if (str != ptr && 'E' != ptr[-1])
  264.                               break;
  265.                   }
  266.  
  267.                   else if (str == ptr)
  268.                         return getop(str);
  269.  
  270.                   else if ('E' == *ptr)
  271.                   {
  272.                         if (!isdigit(ptr[1]) && '-' != ptr[1])
  273.                               return NULL;
  274.                   }
  275.                   else break;
  276.             }
  277.  
  278.             *tptr++ = *ptr++;
  279.       }
  280.       *tptr = NUL;
  281.  
  282.       return token;
  283. }
  284.  
  285. /*
  286. **  Get an operator
  287. */
  288.  
  289. static char *getop(char *str)
  290. {
  291.       *token = *str;
  292.       token[1] = NUL;
  293.       return token;
  294. }
  295.  
  296. /*
  297. **  Remove whitespace & capitalize
  298. */
  299.  
  300. static void pack(char *str)
  301. {
  302.       char *ptr = str, *p;
  303.  
  304.       strupr(str);
  305.  
  306.       for ( ; *ptr; ++ptr)
  307.       {
  308.             p = ptr;
  309.             while (*p && isspace(*p))
  310.                   ++p;
  311.             if (ptr != p)
  312.                   strcpy(ptr, p);
  313.       }
  314. }
  315.